package service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.MoodleException;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

/**
 * Moodle REST Web Services function invoker.
 *
 * @author kgp
 */
public class MoodleRestWSConnector {

    /**
     * Invokes Moodle REST Web Services function.
     *
     * @param restformat transmitted data format: xml or json
     * @param domainName Moodle server domain name
     * @param token Moodle Web Services user's token
     * @param functionName Web Services function name
     * @param urlParameters Web Services function's parameters (send in POST query)
     * @return Moodle REST Web Services function's response
     * @throws model.MoodleException if response is Moodle exception
     */
    public static String moodleWSRestCall(String restformat, String domainName, String token, String functionName, String urlParameters)
            throws MoodleException {

        StringBuilder response = new StringBuilder();

        //Send query
        HttpURLConnection con = sendQuery(restformat, domainName, token, functionName, urlParameters);

        //Receive response
        try {
            InputStream is = con.getInputStream();
            try (BufferedReader rd = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
                String line;

                while ((line = rd.readLine()) != null) {
                    response.append(line);
                    response.append('\r');
                }
                //Handle Moodle exception
                if (response.toString().startsWith("{\"exception")) {
                    throwMoodleException(response);
                } else if ("[]\r".equals(response.toString())) {
                    throw new MoodleException("moodle_exception", "empty", "Empty data!");
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestWSConnector.class
                    .getName()).log(Level.SEVERE, "\n{0}", "Wrong Server Name or Address!");
            throw new MoodleException("connection", "wrongurl", "Wrong Server Name or Address!");
        }
        return response.toString();
    }

    /**
     * Parses Moodle response with exception and wraps errorcode and message in {@code MoodleException} instance.
     *
     * @param response response from Moodle
     * @throws MoodleException encapsulates error code and message
     */
    public static void throwMoodleException(StringBuilder response) throws MoodleException {
        //Response receiving and parsing
        JSONParser parser = new JSONParser();
        Object obj = null;
        JSONObject jsonObj = null;
        try {
            obj = parser.parse(response.toString());
        } catch (ParseException ex) {
            Logger.getLogger(MoodleRestWSConnector.class
                    .getName()).log(Level.SEVERE, "\n{0}", "Exception response parsing error!");
        }
        jsonObj = (JSONObject) obj;
        String errorcode = (String) jsonObj.get("errorcode");
        String message = (String) jsonObj.get("message");
        throw new MoodleException("moodle_exception", errorcode, message);
    }

    /**
     * Send query to Moodle Web Services function.
     *
     * @return {@code HttpURLConnection} instance for response's {@code InputStream} getting from it
     */
    private static HttpURLConnection sendQuery(String restformat, String domainName, String token, String functionName, String urlParameters) {
        HttpURLConnection con = null;
        try {
            //Define message format
            if (restformat.equals("json")) {
                restformat = "&moodlewsrestformat=" + restformat;
            } else {
                restformat = "";
            }
            //Build Moodle REST Web Services function's URL
            String serverurl = domainName + "/webservice/rest/server.php" + "?wstoken=" + token + "&wsfunction=" + functionName + restformat;
            con = (HttpURLConnection) new URL(serverurl).openConnection();
            //Use POST HTTP query and pass parameters in the query body
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            con.setRequestProperty("Content-Language", "en-US");
            con.setDoOutput(true);
            con.setUseCaches(false);
            con.setDoInput(true);
            try (DataOutputStream wr = new DataOutputStream(
                    con.getOutputStream())) {
                //Send query
                wr.writeBytes(urlParameters);
                wr.flush();
            }
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestWSConnector.class.getName()).log(Level.SEVERE, "Open connection or sending data error!", ex);
        }
        return con;
    }
}
